use opencv::{ core::{Mat, Vector}, imgcodecs, prelude::*, videoio };

use tokio::io::AsyncWriteExt;

pub async fn run(){
    let addr = "127.0.0.1:8088";
    // 绑定 TCP 监听器
    let listener = tokio::net::TcpListener::bind( addr ).await.unwrap();
    // 初始化摄像头：代码初始化视频捕获对象（cam），以便从默认网络摄像头（设备索引 0）捕获帧
    let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY).expect("视频捕获失败");
    let mut frame = Mat::default();
    let mut buf = Vector::new();
    // 设置主循环：在主循环中不断监听进入的客户端连接，并为其提供实时视频帧
    loop {
        // 接受客户端连接：在循环中，服务器使用 listener.accept() 函数等待客户端连接。
        // 一旦建立连接，它就会返回一个 TCP 流（stream），用于与客户端通信
        let (mut stream, _) = listener.accept().await.expect("接受连接失败");
        // 捕捉帧并编码： 建立连接后，代码会使用 cam.read(&mut frame) 函数从网络摄像头读取视频帧。
        cam.read(&mut frame).expect("捕获帧失败");
        // 然后使用 imgcodecs::imencode 函数将捕获的帧编码为 JPEG 图像。编码后的图像数据存储在 buf 向量中
        buf.clear();
        let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());
        // 创建响应标头：代码会创建一个 HTTP 响应标头，内容类型为 “multipart/x-mixed-replace”，并指定一个名为 “frame “的边界。
        // 该标头表示将按顺序发送多个图像帧。这样，客户端就能实时接收和显示帧，而无需为每个新帧关闭和重新打开连接
        let response = format!("HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n" );
        if let Err(e) = stream.write_all(response.as_bytes()).await {
            eprintln!("1:{}", e.to_string());
        }
        if let Err(e) = stream.flush().await{
            eprintln!("2:{}", e.to_string())
        }
        // 流帧的内循环：在嵌套循环中，服务器会不断捕获帧、对其进行编码，并以连续流的形式将其发送到客户端。
        // 这个循环确保一旦有新的帧，就会立即捕获并发送
        loop {
            // 编码和发送帧：在内层循环中，服务器再次捕获帧，对其进行编码，并将编码后的数据存储在 buf 向量中。
            // 然后，服务器为图像构建一个带有适当内容类型和内容长度标头的 HTTP 响应。图像数据将使用 stream.write_all 函数发送到客户端的数据流中
            cam.read(&mut frame).expect("捕获帧失败");
            buf.clear();
            let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());

            let image_data = format!("--frame\r\nContent-Type: image/jpeg\r\nContent-Length: {}\r\n\r\n", buf.len());

            if let Err(e) = stream.write_all(image_data.as_bytes()).await {
                eprintln!("3:{}", e.to_string());
                break;
            }
            if let Err(e) = stream.write_all(buf.as_slice()).await {
                eprintln!("4:{}", e.to_string());
                break;
            }
            if let Err(e) =  stream.write_all(b"\r\n").await{
                eprintln!("5:{}", e.to_string());
                break;
            }
            // 刷新流：发送图像数据后，服务器会使用 stream.flush() 函数刷新流，以确保数据立即发送到客户端
            if let Err(e) = stream.flush().await{
                eprintln!("6:{}", e.to_string())
            }
        }
    };
}